package concurrent.c_006_Lock;

import java.util.UUID;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * https://blog.csdn.net/f641385712/article/details/85014986
 * 让所有线程都等待完成后才会继续下一步行动。
 * 默认的构造方法是 CyclicBarrier(int parties)，其参数表示屏障拦截的线程数量，每个线程调用 await 方法告诉 CyclicBarrier 我已经
 * 到达了屏障，然后当前线程被阻塞。
 * CyclicBarrier 还提供一个更高级的构造函数 CyclicBarrier(int parties, Runnable barrierAction)，用于在线程到
 * 达屏障时（前提条件也必须是先达到屏障），优先执行 barrierAction，方便处理更复杂的业务场景。
 * <p>
 * CountDownLatch 的计数器只能使用一次。而 CyclicBarrier 的计数器可以使用 reset() 方法重置。所以 CyclicBarrier 能处理更为复杂的
 * 业务场景，比如如果计算发生错误，可以重置计数器，并让线程们重新执行一次。
 * CyclicBarrier 还提供其他有用的方法，比如 getNumberWaiting 方法可以获得 CyclicBarrier 阻塞的线程数量。isBroken 方法用来知道阻塞的
 * 线程是否被中断。比如以下代码执行完之后会返回 true。
 * CountDownLatch 是减计数方式，而 CyclicBarrier 是加计数方式。
 * CountDownLatch 不可以复用，而 CyclicBarrier 可以复用。
 * <p>
 * 就像生活中我们会约朋友们到某个餐厅一起吃饭，有些朋友可能会早到，有些朋友可能会晚到，但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。
 * 这里的朋友们就是各个线程，餐厅就是 CyclicBarrier。
 */
public class T07_CyclicBarrier {
    public static void main(String[] args) {
        // CyclicBarrier barrier = new CyclicBarrier(20);

        CyclicBarrier barrier = new CyclicBarrier(20, () -> System.out.println("满人"));

        // for (int i = 0; i < 99; i++) { // 程序将永远等待，因为没有第 20 个线程执行 await 方法，即没有第 20 个线程到达屏障，所以之前到达屏障的 19 个线程都不会继续执行。
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                try {
                    barrier.await();
                    System.out.println(UUID.randomUUID().toString()); // 在满人后执行
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}